package com.zdya.combatdocuments.service.impl;


import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zdya.combatdocuments.entity.Authorization;
import com.zdya.combatdocuments.entity.User;
import com.zdya.combatdocuments.entity.vo.AuthorizationVo;
import com.zdya.combatdocuments.entity.vo.ResultEnum;
import com.zdya.combatdocuments.entity.vo.ResultVo;
import com.zdya.combatdocuments.ethereum.EthWallet;
import com.zdya.combatdocuments.mapper.AuthorizationMapper;
import com.zdya.combatdocuments.p2pNetwork.NodeUtil;
import com.zdya.combatdocuments.service.AuthorizationService;
import com.zdya.combatdocuments.service.UserService;
import com.zdya.combatdocuments.util.*;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Service
public class AuthorizationServiceImpl extends ServiceImpl<AuthorizationMapper, Authorization> implements AuthorizationService {

    @Autowired
    NodeUtil nodeUtil;
    @Autowired
    AuthorizationService authorizationService;
    @Autowired
    UserService userService;


    @Override
    public ResultVo<IPage<Authorization>> getAuthorPage(Integer pageNo, Integer pageSize,Authorization authorizationEntity) {
        Page<Authorization> page = new Page<>(pageNo, pageSize);
        LambdaQueryWrapper<Authorization> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotEmpty(authorizationEntity.getName()),Authorization::getName,authorizationEntity.getName());
        queryWrapper.like(StringUtils.isNotEmpty(authorizationEntity.getUsername()),Authorization::getUsername,authorizationEntity.getUsername());
        queryWrapper.like(StringUtils.isNotEmpty(authorizationEntity.getTel()),Authorization::getTel,authorizationEntity.getTel());
        queryWrapper.like(StringUtils.isNotEmpty(authorizationEntity.getElement()),Authorization::getElement,authorizationEntity.getElement());
        queryWrapper.like(StringUtils.isNotEmpty(authorizationEntity.getSeat()),Authorization::getSeat,authorizationEntity.getSeat());
        queryWrapper.like(StringUtils.isNotEmpty(authorizationEntity.getMac()),Authorization::getMac,authorizationEntity.getMac());
        queryWrapper.like(Authorization::getAuthorizeSource,0L);
        queryWrapper.like(Authorization::getAuthorizeStatus,0L);
        IPage<Authorization> iPage = baseMapper.selectPage(page, queryWrapper);
        return ResultVoUtil.success(iPage);
    }

    @Override
    public ResultVo saveAuthor(AuthorizationVo authorizationEntity) {
        try {
            if (authorizationEntity.getExpirationTime() == null || "".equals(authorizationEntity.getExpirationTime())){
                return ResultVoUtil.error("授权文件过期时间未填写");
            }else if (authorizationEntity.getUsername() == null || "".equals(authorizationEntity.getUsername())){
                return ResultVoUtil.error("账户未填写");
            }else if (authorizationEntity.getCpu() == null || "".equals(authorizationEntity.getCpu())){
                return ResultVoUtil.error("被授权者cpu未填写");
            }else if (authorizationEntity.getMac() == null || "".equals(authorizationEntity.getMac())){
                return ResultVoUtil.error("被授权者mac未填写");
            }
            LambdaQueryWrapper<Authorization> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Authorization::getUsername,authorizationEntity.getUsername());
            queryWrapper.eq(Authorization::getElement,authorizationEntity.getElement());
            queryWrapper.eq(Authorization::getSeat,authorizationEntity.getSeat());
            Authorization authorizationEntity1 = baseMapper.selectOne(queryWrapper);
            AjaxResult wallet = EthWallet.createWallet();
            HashMap<String, Object> data = (HashMap<String, Object>) wallet.getData();
            String address = (String) data.get("address");
            String keystore = (String) data.get("keystore");
            Map<String, String> map = SmUtils.creatKeyPair();
            String publicKey = map.get("publicKey");
            String privateKey = map.get("privateKey");
            LocalDate expirationTime = authorizationEntity.getExpirationTime();
            long timestamp = Timestamp.valueOf(expirationTime.atStartOfDay()).getTime();
            String osName = DmcUtils.getOSName();
            osName = osName.toUpperCase();
            if (Objects.isNull(authorizationEntity1)){
                Authorization authorization = new Authorization();
                BeanUtils.copyProperties(authorizationEntity,authorization);
                if ("LINUX".equals(osName)){
                    authorization.setAuthorMac(DmcUtils.getMAC_linux());
                }else {
                    authorization.setAuthorMac(DmcUtils.getLocalMacAddress());
                }
                authorization.setExpirationTime(timestamp);
                authorization.setAddress(address);
                authorization.setKeystore(keystore);
                authorization.setPublicKey(publicKey);
                authorization.setPrivateKey(privateKey);
                authorization.setAuthorizeSource(0L);
                authorization.setAuthorizeStatus(0L);
                baseMapper.insert(authorization);
                return ResultVoUtil.success("添加成功");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResultVoUtil.error(ResultEnum.USER_EXIST.getMessage());
    }

    /**
     * 从节点申请授权
     */
    @Override
    public ResultVo applyAuthor(String primaryIp, AuthorizationVo authorizationVo) {
        ResultVo macAndCpu = userService.findMacAndCpu();
        Map<String, String> data = (Map<String, String>) macAndCpu.getData();
        Authorization authorization = new Authorization();
        authorization.setName(authorizationVo.getName());
        authorization.setUsername(authorizationVo.getUsername());
        authorization.setTel(authorizationVo.getTel());
        authorization.setElement(authorizationVo.getElement());
        authorization.setSeat(authorizationVo.getSeat());
        authorization.setMac(data.get("mac"));
        authorization.setCpu(data.get("cpu"));
        authorization.setIp(nodeUtil.getLocalIp());
        authorization.setPrimaryIp(primaryIp);
        long timestamp = Timestamp.valueOf(authorizationVo.getExpirationTime().atStartOfDay()).getTime();
        authorization.setExpirationTime(timestamp);
        authorization.setAuthorizeStatus(1L);
        authorization.setAuthorizeSource(1L);
        authorization.setPrimaryIp(authorizationVo.getPrimaryIp());
        if (nodeUtil.getLocalIp().equals(authorizationVo.getPrimaryIp())) {
            return ResultVoUtil.error("您不能给自己自动授权， 请走手动授权！");
        }
        try {
            // 如果当前节点，当前申请账号如果已经申请过删除旧的授权记录
            LambdaQueryWrapper<Authorization> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Authorization::getUsername, authorizationVo.getUsername());
            Authorization authorization1 = baseMapper.selectOne(wrapper);
            if (!Objects.isNull(authorization1)) {
                baseMapper.deleteById(authorization1.getId());
            }

            // 发送数据给主节点
            /**调用从节点授权文件接收接口*/
            String url = primaryIp + ":" + nodeUtil.getServerPort() + "/documents/authorization/acceptAuthor";
            HttpRequest request = HttpRequest.post(url);
            // 设置Content-Type为application/json
            request.header("Content-Type", "application/json");

            // 设置请求参数
            authorizationVo.setAuthorizeStatus(1L);
            authorizationVo.setAuthorizeSource(1L);
            authorizationVo.setIp(nodeUtil.getLocalIp());
            JSONObject object = new JSONObject(authorizationVo);
            System.out.println(object);
            request.body(object);
            HttpResponse execute = request.execute();
            System.out.println(execute);
            int status = execute.getStatus();
            if (status == 200) {
                baseMapper.insert(authorization);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultVoUtil.error("申请失败,请联系主节点手动授权！");
        }
        return ResultVoUtil.success("申请成功,请等待授权！");
    }

    /**
     * 从节点接受授权文件
     */
    @Override
    public ResultVo acceptAuthorFile(MultipartFile authorFile, String primaryIp, String username) throws IOException {
        String filePath = "C:\\combatDocuments\\author";
        Path directory = Paths.get(filePath);
        if (!Files.exists(directory)) {
            // 不存在则创建文件夹
            Files.createDirectories(directory);
        }
        // 获取文件原名
        String originalFilename = authorFile.getOriginalFilename();
        String newPath = filePath + "\\"  +originalFilename;
        InputStream inputStream = authorFile.getInputStream();
        FileOutputStream outputStream = new FileOutputStream(new File(newPath));
        byte[] buffer = new byte[1024];
        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
        outputStream.close();
        LambdaQueryWrapper<Authorization> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(primaryIp), Authorization::getPrimaryIp, primaryIp);
        wrapper.eq(StringUtils.isNotBlank(username), Authorization::getUsername, username);
        Authorization authorization = baseMapper.selectOne(wrapper);
        authorization.setAuthorizeStatus(0L);
        baseMapper.updateById(authorization);
        return ResultVoUtil.success("授权已完成！");
    }

    /**
     * 主节点接收申请
     */
    @Override
    public ResultVo acceptAuthor(AuthorizationVo authorizationVo) {
        Authorization authorization = new Authorization();
        BeanUtils.copyProperties(authorizationVo,authorization);
        LocalDate expirationTime = authorizationVo.getExpirationTime();
        long timestamp = Timestamp.valueOf(expirationTime.atStartOfDay()).getTime();
        authorization.setExpirationTime(timestamp);
        authorization.setPrimaryIp(authorizationVo.getPrimaryIp());
        try {
            String osName = DmcUtils.getOSName();
            osName = osName.toUpperCase();
            if ("LINUX".equals(osName)){
                authorization.setAuthorMac(DmcUtils.getMAC_linux());
            }else {
                authorization.setAuthorMac(DmcUtils.getLocalMacAddress());
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        authorization.setAuthorizeSource(0L);
        LambdaQueryWrapper<Authorization> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Authorization::getIp, authorizationVo.getIp());
        wrapper.eq(Authorization::getUsername, authorizationVo.getUsername());
        Authorization authorization1 = baseMapper.selectOne(wrapper);
        if (!Objects.isNull(authorization1)) {
            baseMapper.deleteById(authorization1.getId());
        }
        baseMapper.insert(authorization);
        return ResultVoUtil.success("接收成功");
    }

    /**
     * 主节点审批
     */
    @Override
        public ResultVo approvalAuthor(Long id) {
        try{
            //生成授权文件
            // 创建一个 ByteArrayOutputStream 以捕获 BufferedOutputStream 的输出
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            Authorization authorization = authorizationService.getById(id);
            User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, "admin"));
            authorization.setAuthorName(user.getName());
            Map<String, String> allSn = SerialNumberUtil.getAllSn();
            String cpuid = allSn.get("cpuid");
            authorization.setAuthorCpu(cpuid);

            //数据库修改+回传至从节点
            AjaxResult wallet = EthWallet.createWallet();
            HashMap<String, Object> data = (HashMap<String, Object>) wallet.getData();
            String address = (String) data.get("address");
            String keystore = (String) data.get("keystore");
            Map<String, String> map = SmUtils.creatKeyPair();
            String publicKey = map.get("publicKey");
            String privateKey = map.get("privateKey");
            authorization.setAddress(address);
            authorization.setKeystore(keystore);
            authorization.setPublicKey(publicKey);
            authorization.setPrivateKey(privateKey);

            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream);
            String s = JSON.toJSONString(authorization);
            String encrypt = AESUtils.encrypt(s, "1234567891011121");
            bufferedOutputStream.write(encrypt.getBytes("UTF-8"));
            bufferedOutputStream.flush();
            bufferedOutputStream.close();
            String username = authorization.getUsername();
            File tempFile = createTemporaryFile(byteArrayOutputStream.toByteArray(), username);
            String osName = DmcUtils.getOSName();
            osName = osName.toUpperCase();
            if ("LINUX".equals(osName)){
                authorization.setAuthorMac(DmcUtils.getMAC_linux());
            }else {
                authorization.setAuthorMac(DmcUtils.getLocalMacAddress());
            }
            authorization.setAuthorizeStatus(0L);
            authorization.setPrimaryIp(authorization.getPrimaryIp());
            /**调用从节点授权文件接收接口*/
            String url = authorization.getIp() + ":"+nodeUtil.getServerPort() + "/documents/authorization/acceptAuthorFile";
            HttpRequest requst = HttpRequest.post(url).form("authorFile", tempFile,
                    "primaryIp", authorization.getPrimaryIp(), "username", authorization.getUsername());
            HttpResponse execute = requst.execute();
            FileUtil.del(tempFile);
            if (execute.getStatus() == 200) {
                baseMapper.updateById(authorization);
                return ResultVoUtil.success("回传成功");
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return ResultVoUtil.error("回传失败");
    }

    /**
     * 获取未审批授权信息
     * @param pageNo
     * @param pageSize
     * @param authorizationEntity
     * @return
     */
    @Override
    public ResultVo getAuthorizations(Integer pageNo, Integer pageSize, Authorization authorizationEntity) {
        Page<Authorization> page = new Page<>(pageNo, pageSize);
        LambdaQueryWrapper<Authorization> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotEmpty(authorizationEntity.getName()),Authorization::getName,authorizationEntity.getName());
        queryWrapper.like(StringUtils.isNotEmpty(authorizationEntity.getUsername()),Authorization::getUsername,authorizationEntity.getUsername());
        queryWrapper.like(StringUtils.isNotEmpty(authorizationEntity.getTel()),Authorization::getTel,authorizationEntity.getTel());
        queryWrapper.like(StringUtils.isNotEmpty(authorizationEntity.getElement()),Authorization::getElement,authorizationEntity.getElement());
        queryWrapper.like(StringUtils.isNotEmpty(authorizationEntity.getSeat()),Authorization::getSeat,authorizationEntity.getSeat());
        queryWrapper.like(StringUtils.isNotEmpty(authorizationEntity.getMac()),Authorization::getMac,authorizationEntity.getMac());
        if (authorizationEntity.getAuthorizeSource().longValue() == 0L) {
            queryWrapper.eq(Authorization::getAuthorizeStatus, 1L);
        } else {
            queryWrapper.eq(!Objects.isNull(authorizationEntity.getAuthorizeStatus()), Authorization::getAuthorizeStatus, authorizationEntity.getAuthorizeStatus());
        }
        queryWrapper.eq(!Objects.isNull(authorizationEntity.getAuthorizeSource()), Authorization::getAuthorizeSource, authorizationEntity.getAuthorizeSource());
        if (!Objects.isNull(authorizationEntity.getPrimaryIp())) {
            queryWrapper.eq(!Objects.isNull(authorizationEntity.getPrimaryIp()), Authorization::getPrimaryIp, authorizationEntity.getPrimaryIp());
        }
        IPage<Authorization> iPage = baseMapper.selectPage(page, queryWrapper);
        return ResultVoUtil.success(iPage);
    }


    private static File createTemporaryFile(byte[] content, String username) throws IOException {
        File lceFile = new File(username + ".lce");
        try (OutputStream os = new FileOutputStream(lceFile)) {
            os.write(content);
        }
        return lceFile;
    }
}
